home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / dviware / ln03 / thomas / ln03specials.c < prev    next >
C/C++ Source or Header  |  1990-10-01  |  13KB  |  487 lines

  1. /* This file contains the code that implements the handling of \special's
  2. in Ln03DVI. 
  3.  
  4. Copyright (c) 1985, 1987 by Digital Equipment Corporation. 
  5. Originial Author: Flavio Rose, (...!decwrl!dvinci.dec.com!rose)
  6.  
  7. This version of Ln03DVI is maintained by Matt Thomas.
  8. Please send all bug reports to either:
  9.     ...!decwrl!thebay.dec.com!mthomas (UUCP)
  10.     mthomas@thebay.dec.com (Internet)
  11.  
  12. Right now, the following \special's are implemented: 
  13.  
  14. ln03:defpoint fixnum ( [dimension] , [dimension] )
  15. ln03:connect fixnum [/ fixnum] fixnum [/ fixnum]
  16. ln03:plotfile filename
  17. ln03:resetpoints fixnum fixnum
  18.  
  19. A dimension is a number with optional decimal point, followed by one of pt,
  20. in, pc, cm, mm, bp, dd, cc, and mi. 
  21.  
  22. We try to mimic the functionality of DVIAPS, a program that drives the
  23. Autologic Micro-5 typesetter, written by Textset Inc. of Ann Arbor,
  24. Michigan. This has been done on the basis of user-level documentation
  25. supplied by Textset. This code does not contain any Textset-proprietary
  26. information. 
  27.  
  28. \special's are parsed case-insensitively.
  29.  
  30. Revision history:
  31.  
  32. 10/8/85        Created file, wrote, tested code for ln03:plotfile
  33.  
  34. 10/16/85    ln03:resetpoints, ln03:defpoint, ln03:connect
  35.  
  36. 12/12/85    Corrected bug: ln03:plotfile does not update LN03's
  37.             position to the latest from the DVI file.
  38.  
  39. */
  40.  
  41. #ifdef vms
  42. #include stdio
  43. #include ctype
  44. #include math
  45. #include file
  46. #else
  47. #include <stdio.h>
  48. #include <ctype.h>
  49. #include <math.h>
  50. #endif
  51.  
  52. /* In VMS we declare external variables to be globalref. 
  53. This is not really necessary, just an old habit. */
  54.  
  55. #ifdef vms
  56. #define GLOBAL globaldef
  57. #define EXTERN globalref
  58. #else
  59. #define GLOBAL 
  60. #define EXTERN extern
  61. #endif
  62.  
  63. #define NUMSPECIALS 4
  64.  
  65. GLOBAL char *specialnames[NUMSPECIALS] = { "defpoint",
  66.     "connect", "plotfile", "resetpoints" } ;
  67.  
  68. EXTERN FILE *dvifile,*outfile;
  69.  
  70. /* There are two top-level routines for handling specials, one to be
  71. invoked during pass1, the other to be invoked during pass2. The parameter
  72. that is passed is the size of the \special string. */ 
  73.  
  74. int do_special_pass1 (p) 
  75. int p;
  76. {
  77.     for (; p != 0; p--) getc(dvifile);
  78.     return(0);
  79. }
  80.  
  81. /* Specials get put in a buffer for easier parsing. The buffer is a little
  82. longer than needed to make some things simpler. [[This ought to be
  83. cleaner.]] */ 
  84.  
  85. #define MAXSPECIAL 1000
  86.  
  87. GLOBAL char sb[MAXSPECIAL+7];
  88. GLOBAL int sbp,cstart;
  89.  
  90. /* Do_special_pass2 gets called from the main program to perform special
  91. processing in pass2, the pass in which stuff actually gets written out to
  92. the LN3 output file. The parameter p is the length of the special. */
  93.  
  94. int do_special_pass2 (p)
  95. int p;
  96. {
  97.     char c;
  98.     int i,j;
  99.  
  100. /* Skip whitespace in input */
  101.         
  102.     sbp = 0;
  103.     while (p != 0) {
  104.         c = getc(dvifile);
  105.         p--;
  106.         if (!isspace(c)) {
  107.         sb[sbp] = c;
  108.         sbp = 1;
  109.         break;
  110.     }
  111.     }
  112.     if (sbp == 0) return(1);
  113.  
  114. /* Now we have non-whitespace, read the rest of the special, or as much as
  115. will fit in the buffer. Lowercase the stuff as it is read in. */ 
  116.  
  117.     for (; p != 0; p--) {
  118.         sb[sbp] = tolower(getc(dvifile));
  119.         sbp++;
  120.         if (sbp > MAXSPECIAL) break;
  121.     }
  122.  
  123. /* Put a null as sentinel at the end of the special. */
  124.  
  125.     sb[sbp] = 0;
  126.  
  127. /* Determine whether the special pertains to the ln03, in which case sbpf
  128. will contain "ln03" followed by whitespace or a colon. */ 
  129.  
  130.     if (strncmp(sb,"ln03",sizeof("ln03")-1) != 0) return(1);
  131.     sbp = sizeof("ln03")-1;
  132.  
  133. /* Skip whitespace and one colon */
  134.  
  135.     while (isspace(sb[sbp])) sbp++;
  136.     if (sb[sbp] != ':') return(1);
  137.     sbp++;
  138.  
  139. /* Now, it might be that the special was too long for the special buffer,
  140. so check that out and issue an error message. */ 
  141.  
  142.     if (p != 0) {
  143.         printf("\n \special too long (over %d bytes).",MAXSPECIAL);
  144.         for (; p != 0; p--) getc(dvifile);
  145.         return(1);
  146.     }
  147.  
  148. /* Now determine if the special command is one of those which the driver is
  149. supposed to recognize. As in the DVIAPS program, only the first six bytes
  150. of the command are significant, so plotfile could be written plotfi and
  151. defpoint could be written defpoi. */ 
  152.  
  153.     while (isspace(sb[sbp])) sbp++;
  154.     cstart = sbp;
  155.     while (!isspace(sb[sbp]) && sb[sbp] != '\0') sbp++;
  156.     sb[sbp] = 0;
  157.     sbp++;
  158.  
  159.     for (i = 0; i<NUMSPECIALS; i++)
  160.         if (strncmp(&sb[cstart],specialnames[i],6) == 0) break;
  161.  
  162.     if (i == NUMSPECIALS) {
  163.         printf("\n Unrecognized option '%s' ignored in \special command",
  164.             &sb[cstart]);
  165.         return(1);
  166.     } else {
  167.         switch (i) {
  168.         case 0:
  169.         j = do_defpoint_pass2();
  170.             break;
  171.         case 1:
  172.             j = do_connect_pass2();
  173.             break;
  174.         case 2:
  175.             j = do_plotfile_pass2();
  176.         case 3:
  177.             j = do_resetpoints();
  178.         }
  179.     }
  180. }
  181.  
  182. /* In certain \specials, dimensions may be specified in any of nine
  183. different units of measure. */ 
  184.  
  185. #define MAXUNITS 9
  186.  
  187. GLOBAL char *unit_array[MAXUNITS] = { "pt", "in", "pc", "cm", "mm", "bp", 
  188.     "dd", "cc", "mi" };
  189.  
  190. /* Unit_convert gives a floating point conversion factor from units to
  191. pixels. [[The factor for micas is doubtful.]] */ 
  192.  
  193. #define PIXELS_PER_INCH (300.0)
  194.  
  195. GLOBAL float unit_convert[MAXUNITS] = { PIXELS_PER_INCH/72.27, 
  196.     PIXELS_PER_INCH, 12.0*PIXELS_PER_INCH/72.27,
  197.     PIXELS_PER_INCH/2.54, PIXELS_PER_INCH/25.4, 
  198.     PIXELS_PER_INCH/72.0, (1238.0/1157.0)*PIXELS_PER_INCH/72.27,
  199.     12.0*(1238.0/1157.0)*PIXELS_PER_INCH/72.27, PIXELS_PER_INCH/2540.0 };
  200.  
  201. /* There are 255 point variables, numbered 1 through 255. */
  202.  
  203. #define MAXPOINTS 255
  204.  
  205. GLOBAL int point_hh[MAXPOINTS], point_vv[MAXPOINTS];
  206. GLOBAL int point_present[MAXPOINTS];
  207.  
  208. GLOBAL char *special_mess = "\n Error in \special{ln03:%s...} parameters";
  209.  
  210. /* For the purposes of defpoint, we need to know the current horizontal and
  211. vertical positions in pixels. */ 
  212.  
  213. EXTERN int hh,vv,hoff,voff;
  214.  
  215. /* ln03:defpoint fixnum ( [dimension] , [dimension] ) */
  216.  
  217. int do_defpoint_pass2()
  218. {
  219.     int i,which,hh_val,vv_val;
  220.     float xx_p,yy_p;
  221.  
  222.     which = 0;
  223.     if (scan_fixnum(&which) != 0 || which < 1 || which > MAXPOINTS) {
  224.         printf(special_mess,"defpoint");
  225.         printf("\n Invalid point number (%d)",which);
  226.         return(1);
  227.     }
  228.     while (isspace(sb[sbp]) || sb[sbp] == ',') sbp++;
  229.     hh_val = hh;
  230.     vv_val = vv;
  231.     if (sb[sbp] != '(') goto record_point;
  232.     sbp++;
  233.     while (isspace(sb[sbp])) sbp++;
  234.     if (sb[sbp] == '\0') goto record_point;
  235.     if (sb[sbp] == ',') sbp++;
  236.     else {
  237.         scan_dimension(&hh_val);
  238.         while (isspace(sb[sbp])) sbp++;
  239.         if (sb[sbp] == ',') sbp++;
  240.         else goto record_point;
  241.     } 
  242.     while(isspace(sb[sbp])) sbp++;
  243.     if (sb[sbp] != ')' && sb[sbp] != '\0') scan_dimension(&vv_val);
  244. record_point:
  245.     point_hh[which-1] = hh_val;
  246.     point_vv[which-1] = vv_val;
  247.     point_present[which-1] = 1;
  248.     return(0);
  249. }
  250.  
  251. EXTERN long first_counter;
  252.  
  253. int do_connect_pass2()
  254. {
  255.     int a1,b1,a2,b2,w;
  256.     
  257.     scan_xpoint(&a1,&b1);
  258.     while (isspace(sb[sbp]) || sb[sbp] == ',') sbp++;
  259.     scan_xpoint(&a2,&b2);
  260.     while (isspace(sb[sbp]) || sb[sbp] == ',') sbp++;
  261.     w = 2; /* default width is two pixels ~ 0.4 points */
  262.     if (sb[sbp] != '\0') scan_dimension(&w);
  263.  
  264.     if (first_counter%2 == 0) connect_points(b1,b2,w);
  265.     else connect_points(a1,a2,w);
  266.  
  267.     return(0);
  268. }
  269.  
  270. EXTERN int ln3p,vpset,hh_old;
  271.  
  272. int do_plotfile_pass2()
  273. {
  274.     char buf[512];
  275.     int i,j;
  276.     char c;
  277.  
  278. /* Read filename into array. */ 
  279.  
  280.     while (isspace(sb[sbp])) sbp++;
  281.     i = sbp;
  282.     while (!isspace(sb[sbp]) && sb[sbp] != '\0') sbp++;
  283.     sb[sbp] = 0;
  284.  
  285. /* Try to open the file. [[What is the status of O_RDONLY under Unix? Is
  286. that a 4.2bsd hack that it would be best to leave out?]] */ 
  287.  
  288. #ifdef vms
  289.     j = open(&sb[i],O_RDONLY,0);
  290. #else
  291.     j = open(&sb[i],0,0);
  292. #endif
  293.     if (j == -1) {
  294.         printf("\n Unable to open plotfile %s",&sb[i]);
  295.         return(1);
  296.     }
  297.  
  298. /* In executing the plotfile special, always emit escape sequences to place
  299. the LN03 at the current position of the DVI file, even if it would seem
  300. that the LN03 is already there. We do this in order to be able to emit a
  301. newline at this point. Emitting a newline at this point keeps the line
  302. length of the .ln3 file to <= 16 characters more than the line length of
  303. the plotfile. */ 
  304.  
  305.     fprintf(outfile,"\n\033[%dd\033[%d`",vv+voff,hh+hoff);
  306.  
  307. /* Read stuff from the plotfile, write it to the output file. [[Could this
  308. cause problem with one record being split into two?]] */ 
  309.  
  310.     while((i = read(j,buf,512)) > 0) 
  311.         fwrite(buf,i,1,outfile);
  312.     close(j);
  313.  
  314. /* Now, set the variables ln3p, vpset and hh_old to indicate to the caller
  315. that its recorded value of the current position of the LN03 is no longer
  316. correct. This will make the caller issue absolute positioning commands
  317. before doing any further output to the dvifile. */ 
  318.  
  319.     ln3p = 0;
  320.     vpset = 0;
  321.     hh_old = 30000;
  322.     return(0);
  323. }
  324.  
  325.  
  326. /* Scan_fixnum reads an integer off sb[], starting at sbp and advancing sbp
  327. to the first character past a valid integer. The integer is returned in i.
  328. */ 
  329.  
  330. int scan_fixnum(i)
  331. long *i;
  332. {
  333.     int sbp_save;
  334.  
  335.     sbp_save = sbp;
  336.     *i = atol(&sb[sbp]);
  337.     while(isspace(sb[sbp])) sbp++;
  338.     if (sb[sbp] == '+' || sb[sbp] == '-') sbp++;
  339.     while (isdigit(sb[sbp])) sbp++;
  340.     return(sbp == sbp_save);
  341. }
  342.  
  343.  
  344. /* Scan_flonum reads a flonum (without exponential notation) off sb[],
  345. starting at sbp and advancing sbp to the first character past a valid
  346. flonum. The flonum is returned in x. [[Unfortunately, it is impossible to
  347. use atof or sscanf to implement this function, because they don't allow
  348. flonums like ".3" which don't have any digits before the decimal point.]]
  349. */ 
  350.  
  351. int scan_flonum(x)
  352. float *x;
  353. {
  354.     float j,frac;
  355.     char negative;
  356.     int sbp_save;
  357.  
  358.     sbp_save = sbp;
  359.     negative = 0;
  360.     j = 0.0;
  361.     while (isspace(sb[sbp])) sbp++;
  362.     if (sb[sbp] == '-') { negative = 1; sbp++; }
  363.     else if (sb[sbp] == '+') sbp++;
  364.     while (isdigit(sb[sbp])) { 
  365.         j = 10.0*j + ((float)(sb[sbp] - '0'));
  366.         sbp++;
  367.     }
  368.     if (sb[sbp] == '.') {
  369.         sbp++;
  370.         frac = 0.1;
  371.         while (isdigit(sb[sbp])) {
  372.         j += frac*((float)(sb[sbp] - '0'));
  373.         frac *= 0.1;
  374.         sbp++;
  375.     }
  376.     }
  377.     if (sbp != sbp_save) {
  378.         *x = negative ? (-j) : j;
  379.         return(0);
  380.     } else return(1);
  381.     
  382. }
  383.  
  384.  
  385. /* Scan_dimension tries to parse a dimension off sb[], advancing sbp over
  386. what it can parse. The dimension is converted to pixels and returned in
  387. val. If the unit isn't recognizable, scan_dimension prints an error
  388. message, returns 1 and leaves val unchanged. */ 
  389.  
  390. int scan_dimension(val)
  391. int *val;
  392. {
  393.     float x;
  394.     int i;
  395.  
  396.     x = 0.0;
  397.     scan_flonum(&x);
  398.     while (isspace(sb[sbp])) sbp++;
  399.     for (i = 0; i<MAXUNITS; i++)
  400.         if (strncmp(&sb[sbp],unit_array[i],2) == 0) break;
  401.     if (i == MAXUNITS) {
  402.         printf(special_mess,&sb[cstart]);
  403.         printf("\n No such unit of measure: %.2s",&sb[sbp]);
  404.         return(1);
  405.     }
  406.     sbp += 2;
  407.     x *= unit_convert[i];
  408. #ifdef vms
  409.     *val = (x < 0) ? floor(x-0.5) : floor(x+0.5);
  410. #else
  411.     *val = (x < 0) ? (x-0.5) : (x+0.5);
  412. #endif
  413.     return(0);
  414. }
  415.  
  416. /* Scan_xpoint picks an xpoint off sb[], advancing sbp as usual. If both
  417. parts are present they are returned in a,b; if only one is, it's returned
  418. in both a and b. */ 
  419.  
  420. int scan_xpoint(a,b)
  421. int *a,*b;
  422. {
  423.  
  424.     *a = 0; *b = 0;
  425.     scan_fixnum(a);
  426.     while (isspace(sb[sbp])) sbp++;
  427.     if (sb[sbp] == '/') {
  428.         sbp++;
  429.         scan_fixnum(b);
  430.     } else *b = *a;
  431.     return(0);
  432. }
  433.  
  434. /* int do_rule(xx0,yy0,xx1,yy1) */
  435.  
  436. int connect_points(b1,b2,w) 
  437. int b1,b2;
  438. int w;
  439. {
  440.     int halfw;
  441.  
  442.  
  443.     if (b1 < 1 || b1 > MAXPOINTS || !point_present[b1-1]) {
  444.         printf(special_mess,&sb[cstart]);
  445.         printf("\n Invalid point number (%d)",b1);
  446.         return(1);
  447.     }
  448.     if (b2 < 1 || b2 > MAXPOINTS || !point_present[b2-1]) {
  449.         printf(special_mess,&sb[cstart]);
  450.         printf("\n Invalid point number (%d)",b2);
  451.         return(1);
  452.     }
  453.  
  454.     halfw = w/2;
  455.     if (point_hh[b1-1] == point_hh[b2-1]) 
  456.         do_rule(point_hh[b1-1]-halfw,
  457.             point_vv[b1-1],point_hh[b1-1]+w-1-halfw,
  458.             point_vv[b2-1]);
  459.     else if (point_vv[b1-1] == point_vv[b2-1])
  460.         do_rule(point_hh[b1-1],
  461.             point_vv[b1-1]-halfw,point_hh[b2-1],
  462.             point_vv[b1-1]+w-1-halfw);
  463.     else {
  464.         printf(special_mess,&sb[cstart]);
  465.         printf("\n Can't connect along a diagonal.");
  466.         return(1);
  467.     }        
  468.     return(0);
  469. }
  470.  
  471. int do_resetpoints ()
  472. {
  473.     int a,b;
  474.  
  475.     a = 0;
  476.     scan_fixnum(&a);
  477.     b = 0;
  478.     scan_fixnum(&b);
  479.  
  480.     if (0 < a && a <= b && b <= MAXPOINTS) 
  481.         for (; a <= b; a++) point_present[a] = 0;
  482.     else if (0 < a && a <= MAXPOINTS)
  483.         point_present[a] = 0;
  484.     return(0);
  485. }
  486.  
  487.